package com.cencat.common.response;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 分页响应数据结构
 * 提供标准化的分页查询结果封装
 * 
 * @author cencat
 * @since 2024-01-01
 */
@Data
@NoArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
public class PageResponse<T> implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * 当前页码（从1开始）
     */
    private Long current;

    /**
     * 每页大小
     */
    private Long size;

    /**
     * 总记录数
     */
    private Long total;

    /**
     * 总页数
     */
    private Long pages;

    /**
     * 当前页数据列表
     */
    private List<T> records;

    /**
     * 是否有上一页
     */
    private Boolean hasPrevious;

    /**
     * 是否有下一页
     */
    private Boolean hasNext;

    /**
     * 是否为第一页
     */
    private Boolean isFirst;

    /**
     * 是否为最后一页
     */
    private Boolean isLast;

    /**
     * 构造函数
     * 
     * @param current 当前页码
     * @param size 每页大小
     * @param total 总记录数
     * @param records 数据列表
     */
    public PageResponse(Long current, Long size, Long total, List<T> records) {
        this.current = current;
        this.size = size;
        this.total = total;
        this.records = records;
        this.pages = calculatePages(total, size);
        this.hasPrevious = current > 1;
        this.hasNext = current < this.pages;
        this.isFirst = current == 1;
        this.isLast = current.equals(this.pages);
    }

    /**
     * 构造函数（基于MyBatis-Plus的IPage）
     * 
     * @param page MyBatis-Plus分页对象
     */
    public PageResponse(IPage<T> page) {
        this.current = page.getCurrent();
        this.size = page.getSize();
        this.total = page.getTotal();
        this.pages = page.getPages();
        this.records = page.getRecords();
        this.hasPrevious = this.current > 1;
        this.hasNext = this.current < this.pages;
        this.isFirst = this.current == 1;
        this.isLast = this.current.equals(this.pages);
    }

    // ==================== 静态工厂方法 ====================

    /**
     * 创建空的分页响应
     * 
     * @param current 当前页码
     * @param size 每页大小
     * @param <T> 数据类型
     * @return 空的分页响应
     */
    public static <T> PageResponse<T> empty(Long current, Long size) {
        return new PageResponse<>(current, size, 0L, Collections.emptyList());
    }

    /**
     * 创建分页响应
     * 
     * @param current 当前页码
     * @param size 每页大小
     * @param total 总记录数
     * @param records 数据列表
     * @param <T> 数据类型
     * @return 分页响应
     */
    public static <T> PageResponse<T> of(Long current, Long size, Long total, List<T> records) {
        return new PageResponse<>(current, size, total, records);
    }

    /**
     * 基于MyBatis-Plus的IPage创建PageResponse
     * 
     * @param page MyBatis-Plus分页对象
     * @param <T> 数据类型
     * @return PageResponse实例
     */
    public static <T> PageResponse<T> of(IPage<T> page) {
        return new PageResponse<>(page);
    }

    /**
     * 从MyBatis-Plus的IPage创建PageResponse（别名方法）
     * 
     * @param page MyBatis-Plus分页对象
     * @param <T> 数据类型
     * @return PageResponse实例
     */
    public static <T> PageResponse<T> fromIPage(IPage<T> page) {
        return new PageResponse<>(page);
    }

    /**
     * 创建单页响应（不分页）
     * 
     * @param records 数据列表
     * @param <T> 数据类型
     * @return 分页响应
     */
    public static <T> PageResponse<T> single(List<T> records) {
        if (records == null) {
            records = Collections.emptyList();
        }
        return new PageResponse<>(1L, (long) records.size(), (long) records.size(), records);
    }

    // ==================== 数据转换方法 ====================

    /**
     * 转换数据类型
     * 
     * @param converter 转换函数
     * @param <R> 目标数据类型
     * @return 转换后的分页响应
     */
    public <R> PageResponse<R> convert(Function<T, R> converter) {
        List<R> convertedRecords = this.records == null ? 
            Collections.emptyList() : 
            this.records.stream().map(converter).collect(Collectors.toList());
        
        PageResponse<R> result = new PageResponse<R>();
        result.current = this.current;
        result.size = this.size;
        result.total = this.total;
        result.pages = this.pages;
        result.records = convertedRecords;
        result.hasPrevious = this.hasPrevious;
        result.hasNext = this.hasNext;
        result.isFirst = this.isFirst;
        result.isLast = this.isLast;
        
        return result;
    }

    /**
     * 转换为ApiResponse格式
     * 
     * @return ApiResponse包装的分页响应
     */
    public ApiResponse<PageResponse<T>> toApiResponse() {
        return ApiResponse.success(this);
    }

    /**
     * 转换为ApiResponse格式（自定义消息）
     * 
     * @param message 响应消息
     * @return ApiResponse包装的分页响应
     */
    public ApiResponse<PageResponse<T>> toApiResponse(String message) {
        return ApiResponse.success(message, this);
    }

    // ==================== 工具方法 ====================

    /**
     * 计算总页数
     * 
     * @param total 总记录数
     * @param size 每页大小
     * @return 总页数
     */
    private Long calculatePages(Long total, Long size) {
        if (total == null || total <= 0 || size == null || size <= 0) {
            return 0L;
        }
        return (total + size - 1) / size;
    }

    /**
     * 判断是否为空页面
     * 
     * @return true-空页面，false-非空页面
     */
    public boolean isEmpty() {
        return this.records == null || this.records.isEmpty();
    }

    /**
     * 判断是否有数据
     * 
     * @return true-有数据，false-无数据
     */
    public boolean hasContent() {
        return !isEmpty();
    }

    /**
     * 获取当前页数据数量
     * 
     * @return 当前页数据数量
     */
    public int getNumberOfElements() {
        return this.records == null ? 0 : this.records.size();
    }

    /**
     * 获取起始记录索引（从0开始）
     * 
     * @return 起始记录索引
     */
    public Long getOffset() {
        return (this.current - 1) * this.size;
    }

    /**
     * 获取结束记录索引（从0开始，不包含）
     * 
     * @return 结束记录索引
     */
    public Long getEndOffset() {
        return Math.min(getOffset() + this.size, this.total);
    }

    /**
     * 获取当前页显示的记录范围描述
     * 
     * @return 记录范围描述，如："1-10 of 100"
     */
    public String getDisplayRange() {
        if (isEmpty()) {
            return "0 of " + this.total;
        }
        
        long start = getOffset() + 1;
        long end = Math.min(start + getNumberOfElements() - 1, this.total);
        return start + "-" + end + " of " + this.total;
    }

    /**
     * 获取分页摘要信息
     * 
     * @return 分页摘要信息
     */
    public PageSummary getSummary() {
        return new PageSummary(
            this.current,
            this.size,
            this.total,
            this.pages,
            getNumberOfElements(),
            this.hasPrevious,
            this.hasNext,
            this.isFirst,
            this.isLast
        );
    }

    /**
     * 获取导航信息
     * 
     * @param displayPages 显示的页码数量
     * @return 导航信息
     */
    public PageNavigation getNavigation(int displayPages) {
        return new PageNavigation(this.current, this.pages, displayPages);
    }

    /**
     * 获取导航信息（默认显示5个页码）
     * 
     * @return 导航信息
     */
    public PageNavigation getNavigation() {
        return getNavigation(5);
    }

    // ==================== 内部类 ====================

    /**
     * 分页摘要信息
     */
    @Data
    @NoArgsConstructor
    public static class PageSummary implements Serializable {
        private static final long serialVersionUID = 1L;
        
        private Long current;
        private Long size;
        private Long total;
        private Long pages;
        private Integer numberOfElements;
        private Boolean hasPrevious;
        private Boolean hasNext;
        private Boolean isFirst;
        private Boolean isLast;

        public PageSummary(Long current, Long size, Long total, Long pages, 
                          Integer numberOfElements, Boolean hasPrevious, Boolean hasNext, 
                          Boolean isFirst, Boolean isLast) {
            this.current = current;
            this.size = size;
            this.total = total;
            this.pages = pages;
            this.numberOfElements = numberOfElements;
            this.hasPrevious = hasPrevious;
            this.hasNext = hasNext;
            this.isFirst = isFirst;
            this.isLast = isLast;
        }
    }

    /**
     * 分页导航信息
     */
    @Data
    @NoArgsConstructor
    public static class PageNavigation implements Serializable {
        private static final long serialVersionUID = 1L;
        
        private Long current;
        private Long total;
        private Long startPage;
        private Long endPage;
        private List<Long> pageNumbers;
        private Boolean showPrevious;
        private Boolean showNext;
        private Boolean showFirst;
        private Boolean showLast;

        public PageNavigation(Long current, Long total, int displayPages) {
            this.current = current;
            this.total = total;
            
            // 计算显示的页码范围
            long half = displayPages / 2;
            this.startPage = Math.max(1, current - half);
            this.endPage = Math.min(total, this.startPage + displayPages - 1);
            
            // 调整起始页码
            if (this.endPage - this.startPage + 1 < displayPages) {
                this.startPage = Math.max(1, this.endPage - displayPages + 1);
            }
            
            // 生成页码列表
            this.pageNumbers = java.util.stream.LongStream
                .rangeClosed(this.startPage, this.endPage)
                .boxed()
                .collect(Collectors.toList());
            
            // 设置导航按钮显示状态
            this.showPrevious = current > 1;
            this.showNext = current < total;
            this.showFirst = this.startPage > 1;
            this.showLast = this.endPage < total;
        }
    }

    /**
     * 分页构建器
     */
    public static class Builder<T> {
        private Long current = 1L;
        private Long size = 10L;
        private Long total = 0L;
        private List<T> records = Collections.emptyList();

        public Builder<T> current(Long current) {
            this.current = current;
            return this;
        }

        public Builder<T> size(Long size) {
            this.size = size;
            return this;
        }

        public Builder<T> total(Long total) {
            this.total = total;
            return this;
        }

        public Builder<T> records(List<T> records) {
            this.records = records;
            return this;
        }

        public PageResponse<T> build() {
            return new PageResponse<>(this.current, this.size, this.total, this.records);
        }
    }

    /**
     * 创建构建器
     * 
     * @param <T> 数据类型
     * @return 构建器实例
     */
    public static <T> Builder<T> builder() {
        return new Builder<>();
    }

    @Override
    public String toString() {
        return String.format("PageResponse{current=%d, size=%d, total=%d, pages=%d, records=%d}",
            this.current, this.size, this.total, this.pages, getNumberOfElements());
    }
}